import uvicorn
from enum import Enum
from typing import Optional, List
from fastapi import FastAPI, Query, Path, Body, Cookie, Response, Header
from pydantic import BaseModel

app = FastAPI(title='大标题',description='整体描述')

class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[bool] = None

    class Config:
    	schema_extra = {
    		"example": {
    			"name": "jingluo",
    			"description": "a good man",
    			"price": 20.9,
    			"tax": 3.2
    		}
    	}

class ResonseItem(BaseModel):
    name: str
    description: Optional[str] = None
    price: float = 100.5
    tax: Optional[float] = None
    tags: List[str] = []

class ModelName(str, Enum):
	alexnet = "alexnet"
	resnet = "resnet"
	lenet = "lenet"

# http://127.0.0.1:8000/
@app.get("/",summary='根路径',description='无任何参数，主要输出Hello World',tags=['前端'])
async def read_root():
	return {"Hello": "World"}

# http://127.0.0.1:8000/items/1?q=hello
@app.get("/items/{item_id}",summary='带参数接口',description='必填item_id，可选q',tags=['前端'])
async def read_item(item_id: int, q: Optional[str] = None):
	return {"item_id": item_id, "q": q}

# http://127.0.0.1:8000/items/1
@app.put("/items/{item_id}",summary='带参数接口',description='必填item_id，可选item结构体',tags=['前端'])
def update_item(item_id: int, item: Item):
    return {"item_name": item.name, "item_id": item_id}


# 当使用Query时，且这个值必需的话，可以将`...`用作第一个参数值
# http://127.0.0.1:8000/items/?q=13131313131
@app.get("/items/",summary='不带参数接口',description='无必填，可选q，限制为3-12之间字符长度，并且更新q到results',tags=['前端'])
async def read_items(q: str = Query(None, min_length = 3, max_length = 12, regex="^1(3([0-35-9]\\d|4[1-8])|4[14-9]\\d|5([0125689]\\d|7[1-79])|66\\d|7[2-35-8]\\d|8\\d{2}|9[13589]\\d)\\d{7}$")):
	results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
	if q:
		results.update({"q": q})
	return results

# 添加title
@app.get("/items/addTitle/",summary='添加title',description='无必填，可选q，限制为3个以上字符长度',tags=['前端'])
async def read_items(
    q: Optional[str] = Query(None, title="这是啥", min_length=3)
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

# http://127.0.0.1:8000/items/setAlias/item-query=123
# 设置别名
@app.get("/items/setAlias/",summary='设置别名',description='无必填，可选q，别名为item-query',tags=['前端'])
async def read_items(q: Optional[str] = Query(None, alias="item-query")):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

# http://127.0.0.1:8000/items/setAlias/item-query=123
# 弃用参数
@app.get("/items/discard/",summary='弃用参数',description='无必填，可选q，限制为3-50之间字符长度，并且更新q到results，展示弃用',tags=['前端'])
async def read_items(
    q: Optional[str] = Query(
        None,
        alias="item-query",
        title="Query string",
        description="Query string for the items to search in the database that have a good match",
        min_length=3,
        max_length=50,
        deprecated=True,
    )
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results


# http://127.0.0.1:8000/model/alexnet
@app.get("/model/{model_name}",summary='使用Pydantic模型',description='Pydantic模型中BaseModel',tags=['前端'])
async def get_model(model_name: ModelName):
	if model_name == ModelName.alexnet:
		return {"model_name": model_name, "message": "Deep Learning FTW!"}
	if model_name.value == "lenet":
		return {"model_name": model_name, "message": "LeCNN all the images"}
	return {"model_name": model_name, "message": "Have some residuals"}

@app.get("/item/", summary='多次出现的查询参数q', description='当你使用 Query 显式地定义查询参数时，你还可以声明它去接收一组值，或换句话来说，接收多个值。', tags=['前端'])
async def read_item(q: Optional[List[str]] = Query(None)):
	query_items = {"q": q}
	return query_items

# http://127.0.0.1:8000/items/path/1
# 使用Path进行为路径参数声明相同类型和数值的校验
# gt：大于
# le：小于或等于
# 同样适用浮点数，必须要大于0
@app.get("/items/path/{item_id}",summary='使用path进行类型和数值校验',description='必填item_id，并且大于1的整数',tags=['前端'])
async def read_items(
    item_id: int = Path(..., title="item的id", gt=1),
    q: Optional[str] = Query(None, alias="item-query"),
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    return results

# 携带请求参数键的请求体
@app.put("/items/bring/{item_id}", summary='携带请求参数键的请求体', description='必填item_id，可选参数item', tags=['前端'])
async def update_item(item_id: int, item: Item = Body(..., embed=True)):
    results = {"item_id": item_id, "item": item}
    return results

@app.get("/items/cookie/", summary='使用cookie如同使用query和path参数', description='无必填', tags=['前端'])
async def get_cookie(ads_id: Optional[str] = Cookie(None)):
    return {"ads_id": ads_id}

@app.get("/items/user_agent/", summary='使用Header如同使用query和path参数', description='无必填', tags=['前端'])
async def get_user_agent(user_agent: Optional[str] = Header(None, convert_underscores=False), x_token: Optional[List[str]] = Header(None)):
    return {
        "user_agent": user_agent,
        "x-token": x_token
    }

# response_model_exclude_unset 去掉无用的
# response_model_include 包含
# response_model_exclude 抛出
@app.post("/items/response_model/", response_model=ResonseItem, response_model_exclude_unset=True, summary='自定义response,响应抛出默认值', description='必填参数', tags=['前端'])
async def response_model(item: ResonseItem):
    return item

if __name__ == '__main__':
    uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)